/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package treeship.core.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import treeship.core.archetype.impl.ArchetypeFamilyImpl;
import treeship.core.archetype.impl.ArchetypePropertyImpl;
import treeship.core.archetype.impl.ArchetypeShipImpl;
import treeship.core.archetype.impl.ComponentContextImpl;
import treeship.core.archetype.impl.PropertyContextImpl;
import treeship.core.service.ArchetypesRepository;
import treeship.core.service.Constants;
import treeship.core.service.xml.XMLReader;

/**
 * 
 * @author Moonchild
 */
public class ArchetypesRepositoryImpl extends ArchetypesRepository {

	private Map<String, ArchetypeShipImpl> ships = new HashMap<String, ArchetypeShipImpl>();
	private List<ArchetypeShipImpl> listShips = new ArrayList<ArchetypeShipImpl>();
	private Map<String, ArchetypePropertyImpl> properties = new HashMap<String, ArchetypePropertyImpl>();
	private List<ArchetypePropertyImpl> listProperties = new ArrayList<ArchetypePropertyImpl>();
	private Map<String, ArchetypeFamilyImpl> families = new HashMap<String, ArchetypeFamilyImpl>();
	private List<ArchetypeFamilyImpl> listFamilies = new ArrayList<ArchetypeFamilyImpl>();
	private ContextDataImpl contextData = new ContextDataImpl();

	public ArchetypesRepositoryImpl() {
	}

	@Override
	public ArchetypeShipImpl getArchetypeShipFor(String s) {
		return ships.get(s);
	}

	@Override
	public ArchetypePropertyImpl getArchetypePropertyFor(String s) {
		return properties.get(s);
	}

	@Override
	public ArchetypeFamilyImpl getArchetypeFamilyFor(String s) {
		return families.get(s);
	}

	public void addArchetypeShip(ArchetypeShipImpl arch) {
		if (!ships.containsKey(arch.getName())) {
			ships.put(arch.getName(), arch);
			listShips.add(arch);
		}
	}

	public void addArchetypeProperty(ArchetypePropertyImpl arch) {
		if (!properties.containsKey(arch.getName())) {
			properties.put(arch.getName(), arch);
			listProperties.add(arch);
		}
	}

	public void addArchetypeFamily(ArchetypeFamilyImpl arch) {
		if (!families.containsKey(arch.getName())) {
			families.put(arch.getName(), arch);
			listFamilies.add(arch);
		}
	}

	@Override
	public String toString() {
		StringBuffer buff = new StringBuffer();
		buff.append("Entities\n");
		for (ArchetypeShipImpl ship : ships.values()) {
			buff.append(ship.toString() + "\n");
		}
		buff.append("\n");
		buff.append("Properties\n");
		for (ArchetypePropertyImpl pro : properties.values()) {
			buff.append(pro.toString() + "\n");
		}
		buff.append("\n");
		return buff.toString();

	}

	public void normalizeWeights() {
		for (ArchetypeShipImpl shp : ships.values()) {
			shp.normalizeWeights();
		}
	}

	@Override
	public List<ArchetypeShipImpl> getArchetypeShips() {
		return listShips;
	}

	@Override
	public List<ArchetypePropertyImpl> getArchetypeProperties() {
		return listProperties;
	}

	@Override
	public ContextDataImpl getContextData() {
		return contextData;
	}

	@Override
	public List<ArchetypeFamilyImpl> getArchetypeFamilies() {
		return listFamilies;
	}

	public void dangerous_removeArchetypeShip(ArchetypeShipImpl asi) {
		for (ArchetypeShipImpl cursor : listShips) {
			List<ComponentContextImpl> toDelete = new ArrayList<ComponentContextImpl>();
			for (ComponentContextImpl cci : cursor.getComponents()) {
				if (cci.getComponent() == asi) {
					toDelete.add(cci);
				}
			}
			for (ComponentContextImpl cci : toDelete) {
				cursor.dangerous_removeComponent(cci);
			}
		}

		listShips.remove(asi);
		ships.values().remove(asi);

	}

	public void dangerous_removeArchetypeProperty(ArchetypePropertyImpl api) {
		for (ArchetypeShipImpl cursor : listShips) {
			List<PropertyContextImpl> toDelete = new ArrayList<PropertyContextImpl>();
			for (PropertyContextImpl cci : cursor.getProperties()) {
				if (cci.getProperty() == api) {
					toDelete.add(cci);
				}
			}
			for (PropertyContextImpl cci : toDelete) {
				cursor.dangerous_removeProperty(cci);
			}
		}

		listProperties.remove(api);
		properties.values().remove(api);
	}

	public String getToXml() {
		StringBuffer b = new StringBuffer();
		b.append("<?xml version=\"1.0\" encoding=\"windows-1252\"?>");
		b.append("\n");
		b.append("<!-- <!DOCTYPE root PUBLIC \"-//InterMoon/Treeship//EN\" \"hierarchy.dtd\"> -->");
		b.append("\n");
		b.append("<root>");
		b.append("\n");
		b.append(XMLReader.openTag(Constants.GLOBALIDS));
		b.append("\n");

		b.append("\t");
		b.append(XMLReader.encodeTagAndValue(Constants.IDDIMENSION,
				getContextData().getIdDimension()));
		b.append("\n");

		b.append("\t");
		b.append(XMLReader.encodeTagAndValue(Constants.IDFREESPACE,
				getContextData().getIdFreespace()));
		b.append("\n");

		b.append("\t");
		b.append(XMLReader.encodeTagAndValue(Constants.IDPOSITION,
				getContextData().getIdPosition()));
		b.append("\n");

		b.append("\t");
		b.append(XMLReader.encodeTagAndValue(Constants.IDSPEED,
				getContextData().getIdSpeed()));
		b.append("\n");

		b.append("\t");
		b.append(XMLReader.encodeTagAndValue(Constants.SOLIDITYENABLED,
				getContextData().isSolidityEnabled() ? Constants.TRUE
						: Constants.FALSE));
		b.append("\n");

		// buff.append("<"+ +">\n");

		b.append(XMLReader.closeTag(Constants.GLOBALIDS));
		b.append("\n");

		b.append(XMLReader.openTag(Constants.FAMILYLIST));
		b.append("\n");

		for (ArchetypeFamilyImpl pr : listFamilies) {
			b.append("\t");
			b.append(XMLReader.openTagAndLeaveOpen(Constants.FAMILYDEFINITION));
			b.append(XMLReader.encodeAttribute(Constants.NAME, pr.getName()));
			b.append("/>");
			b.append("\n");
		}

		b.append(XMLReader.closeTag(Constants.FAMILYLIST));
		b.append("\n");

		b.append(XMLReader.openTag(Constants.PROPERTYLIST));
		b.append("\n");

		for (ArchetypePropertyImpl pr : listProperties) {
			b.append("\t");
			b.append(XMLReader
					.openTagAndLeaveOpen(Constants.PROPERTYDEFINITION));
			b.append(XMLReader.encodeAttribute(Constants.NAME, pr.getName()));
			b.append(XMLReader.encodeAttribute(Constants.ID, pr.getId()));
			if (pr.getFocus() != null) {
				b.append(XMLReader.encodeAttribute(Constants.FOCUS, pr
						.getFocus().getName()));
			}
			b.append("/>");
			b.append("\n");
		}

		b.append(XMLReader.closeTag(Constants.PROPERTYLIST));
		b.append("\n");

		b.append(XMLReader.openTag(Constants.ENTITYLIST));
		b.append("\n");

		for (ArchetypeShipImpl sh : listShips) {
			b.append("\t");
			b.append(XMLReader.openTag(Constants.ENTITY));
			b.append("\n");
			b.append("\t\t");
			b.append(XMLReader.encodeTagAndValue(Constants.NAME, sh.getName()));
			b.append("\n");

			if (sh.getFamily() != null) {
				b.append("\t\t");
				b.append(XMLReader.encodeTagAndValue(Constants.FAMILY, sh
						.getFamily().getName()));
				b.append("\n");
			}

			b.append("\t\t");
			b.append(XMLReader.openTagAndLeaveOpen(Constants.DIMENSION));
			b.append(XMLReader.encodeAttribute(Constants.VARIANCE, sh
					.getDimensionContext().getDimensionVariant()));
			b.append(">");
			b.append(sh.getDimensionContext().getDimensionAverage());
			b.append(XMLReader.closeTag(Constants.DIMENSION));
			b.append("\n");

			b.append("\t\t");
			b.append(XMLReader.openTagAndLeaveOpen(Constants.FREESPACE));
			b.append(XMLReader.encodeAttribute(Constants.VARIANCE, sh
					.getDimensionContext().getFreeSpaceVariant()));
			b.append(">");
			b.append(sh.getDimensionContext().getFreeSpaceAverage());
			b.append(XMLReader.closeTag(Constants.FREESPACE));
			b.append("\n");

			b.append("\t\t");
			b.append(XMLReader.encodeTagAndValue(Constants.OPEN,
					sh.isOpen() ? Constants.TRUE : Constants.FALSE));
			b.append("\n");

			b.append("\t\t");
			b.append(XMLReader.encodeTagAndValue(Constants.SOLID,
					sh.isSolid() ? Constants.TRUE : Constants.FALSE));
			b.append("\n");

			b.append("\t\t");
			b.append(XMLReader.openTagAndLeaveOpen(Constants.SPEED));
			b.append(XMLReader.encodeAttribute(Constants.VARIANCE, sh
					.getDimensionContext().getSpeedVariant()));
			b.append(">");
			b.append(sh.getDimensionContext().getSpeedAverage());
			b.append(XMLReader.closeTag(Constants.SPEED));
			b.append("\n");

			b.append("\t\t");
			b.append(XMLReader.openTag(Constants.PROPERTIES));
			b.append("\n");
			for (PropertyContextImpl pci : sh.getProperties()) {
				b.append("\t\t\t");
				b.append(XMLReader.openTagAndLeaveOpen(Constants.PROPERTY));
				b.append(XMLReader.encodeAttribute(Constants.NAME, pci
						.getProperty().getName()));
				b.append(XMLReader.encodeAttribute(Constants.DEFAULT,
						pci.getAverage()));
				b.append(XMLReader.encodeAttribute(Constants.VARIANCE,
						pci.getVariant()));
				b.append(XMLReader.encodeAttribute(Constants.MIN, pci.getMin()));
				b.append("/>");
				b.append("\n");

			}

			b.append("\t\t");
			b.append(XMLReader.closeTag(Constants.PROPERTIES));
			b.append("\n");
			if (!sh.getComponents().isEmpty()) {
				b.append("\t\t");
				b.append(XMLReader.openTag(Constants.CHILDREN));
				b.append("\n");
				for (ComponentContextImpl asi : sh.getComponents()) {
					b.append("\t\t\t");
					b.append(XMLReader.openTagAndLeaveOpen(Constants.CHILD));
					b.append(XMLReader.encodeAttribute(Constants.NAME, asi
							.getComponent().getName()));
					b.append(XMLReader.encodeAttribute(Constants.WEIGHT,
							asi.getWeight()));
					b.append("/>");
					b.append("\n");

				}

				b.append("\t\t");
				b.append(XMLReader.closeTag(Constants.CHILDREN));
				b.append("\n");
			}

			if (!sh.getCreatives().isEmpty()) {
				b.append("\t\t");
				b.append(XMLReader.openTag(Constants.CREATIVES));
				b.append("\n");
				for (ArchetypeShipImpl asi : sh.getCreatives()) {
					b.append("\t\t\t");
					b.append(XMLReader.openTagAndLeaveOpen(Constants.CREATIVE));
					b.append(XMLReader.encodeAttribute(Constants.NAME,
							asi.getName()));
					b.append("/>");
					b.append("\n");
				}
				b.append("\t\t");
				b.append(XMLReader.closeTag(Constants.CREATIVES));
				b.append("\n");
			}

			b.append("\t");
			b.append(XMLReader.closeTag(Constants.ENTITY));
			b.append("\n");
		}

		b.append(XMLReader.closeTag(Constants.ENTITYLIST));
		b.append("\n");

		b.append(XMLReader.openTag(Constants.ACTIONLIST));
		b.append("\n");
		b.append(XMLReader.closeTag(Constants.ACTIONLIST));
		b.append("\n");

		b.append("</root>");

		return b.toString();
	}

}
